package com.bzg.baseSpringComponent.metaData;

import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;

import java.io.IOException;

/**
 * 元数据信息，spring在整个执行过程中会大量涉及类、注解等相关信息。所以spring提供了MetaData相关类来封装一个类的相关信息
 * @see org.springframework.core.type.ClassMetadata 用于封装class的相关信息
 * @see org.springframework.core.type.AnnotationMetadata 用于封装类及方法上注解相关元数据信息。
 * @see org.springframework.core.type.MethodMetadata 用于封装method元数据
 * @see org.springframework.core.type.classreading.MetadataReader 用于元数据信息的读取
 * */
public class MetaDataStyle {

	public static void main(String[] args) throws IOException {
		// 创建一个工厂（metaDataReader目前唯一子类SimpleMetadataReader无法直接创建，需要借助工厂来创建）
		SimpleMetadataReaderFactory simpleMetadataReaderFactory = new SimpleMetadataReaderFactory();
		MetadataReader metadataReader = simpleMetadataReaderFactory.getMetadataReader("com.bzg.baseSpringComponent.metaData.User");
		metadataReader.getClassMetadata();
		metadataReader.getAnnotationMetadata();

		/**
		 * 这里我说一下，为什么getMetadataReader()方法内部传的是一个字符串或者一个Resource
		 * 这是因为，元数据的信息读取spring并没有采用反射来处理，而是直接加载一个class的流，然后通过ASM解析
		 * 好处：
		 * 无需将这个类加载到jvm，因为是直接读取的class文件的流，然后通过asm技术直接从流中解析出这个类的信息(类的所有信息都是存在class文件中的)
		 * @see org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan(String...) 
		 * 例如，spring在扫描Component组件时，需要将指定包下的所有类文件都加载然后判断是否为一个组件，如果直接将这个类文件通过类加载器加载到jvm再去用
		 * 反射判断是否有Component注解，这样大量的类都将被加载到jvm(即使他不是一个组件)，这就使得jvm容易占用大量内存。
		 * 所以spring采用MetadataReader直接去读class文件流，这样就避免了类加载到jvm。换句话说，类应该是使用时才加载。
		 * */
	}
}
